package com.rzx.mybackend.consumer;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.rzx.mybackend.entity.BuyMerchandise;
import com.rzx.mybackend.enums.MerchandiseOrderStatus;
import com.rzx.mybackend.service.BuyMerchandiseService;
import com.rzx.mybackend.service.MerchandiseService;
import com.rzx.mybackend.utils.CommonUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * OutTimeOrderConsumer
 *
 * @author renzhexian
 * @date 2025/8/22
 */

@Component
@RequiredArgsConstructor
@Slf4j
public class OutTimeOrderConsumer {

    private final BuyMerchandiseService buyMerchandiseService;

    private final MerchandiseService merchandiseService;

    private final CommonUtils commonUtils;

    @Transactional
    @RabbitListener(queues = "${spring.rabbitmq.timeOrderDead.queue_name}")
    public void getTimeOrder(List<BuyMerchandise> buyMerchandiseList) {
        System.out.println("TimeOrderConsumer开始验证订单: " + buyMerchandiseList.stream().map(BuyMerchandise::getOrderCode).toList());
        // 校验订单状态是否已经支付，未支付取消订单
        List<Long> orderIdList = buyMerchandiseList.stream().map(BuyMerchandise::getId).toList();
        // 查询状态为未支付订单
        List<BuyMerchandise> unPayOrderList = getUnPayOrderList(orderIdList);
        if (!unPayOrderList.isEmpty()){
            // 订单取消后，增加商品库存
            // 按商品ID分组并统计每个商品的总购买数量
            Map<Long, Integer> totalQuantityByMerchandise = unPayOrderList.stream()
                    .collect(Collectors.groupingBy(
                            BuyMerchandise::getMerchandiseId,
                            Collectors.summingInt(BuyMerchandise::getMerchandise_num)
                    ));

            // 根据商品Id构建redis库存key
            for (Long merchandiseId :totalQuantityByMerchandise.keySet()) {
                RLock rLock = commonUtils.generateStockRedisRLock(merchandiseId);

                try {
                    boolean isLocked = rLock.tryLock(5, 10, TimeUnit.SECONDS);

                    if (!isLocked) {
                        // todo: 获取锁失败，记录日志，稍后重试
                        throw new RuntimeException("商品" + merchandiseId + "库存处理繁忙，请稍后重试");
                    }

                    try {
                        /*
                        执行库存回退
                         */
                        merchandiseService.refundStock(merchandiseId, totalQuantityByMerchandise.get(merchandiseId));
                    } catch (Exception e) {
                        // 处理业务异常
                        log.error("处理超时订单时发生异常", e);
                        throw e;
                    } finally {
                        if (rLock.isHeldByCurrentThread()) {
                            rLock.unlock();
                        }
                    }

                    /*
                    批量取消订单
                     */
                    buyMerchandiseService.cancelOrder(unPayOrderList.stream().map(BuyMerchandise::getId).toList());

                } catch (InterruptedException e) {
                    // 防止锁泄漏
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("获取锁被中断", e);
                }
            }


        }
    }

    private List<BuyMerchandise> getUnPayOrderList(List<Long> orderIdList) {
        LambdaQueryWrapper<BuyMerchandise> buyMerchandiseLambdaQueryWrapper = new LambdaQueryWrapper<>();
        buyMerchandiseLambdaQueryWrapper.in(BuyMerchandise::getId, orderIdList);
        buyMerchandiseLambdaQueryWrapper.in(BuyMerchandise::getOrderStatus, MerchandiseOrderStatus.UNPAID.getCode());
        return buyMerchandiseService.list(buyMerchandiseLambdaQueryWrapper);
    }


}

